﻿#region 程序集引用
using System;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
#endregion

#region 版权注释
/*===========================================================================
// Copyright (C) 2017 Zhang.cn，并保留所有 
// 作者：吴岸标 QQ:405403610
// 创建日期：2017-09-03
// 功能描述： zip 文件压缩与解压
===========================================================================*/
#endregion

namespace Zhang
{
    namespace Utils
    {
        /// <summary>
        ///  zip 文件压缩与解压
        /// </summary>
        public class Zip
        {
            /// <summary>
            /// 创建zip文件
            /// </summary>
            /// <param name="srcDir">待压缩的文件夹</param>
            /// <param name="zipFilePath">压缩后的zip文件路径（包括文件名）</param>
            /// <param name="errMsg">错误信息</param>
            void CreateZipByDictory(string srcDir, string zipFilePath, out string errMsg)
            {
                string[] arrFilesName;
                byte[] btBuffer;
                ZipEntry zipEntry;
                int scBytes;
                ZipOutputStream s;

                errMsg = string.Empty;

                if (!Directory.Exists(srcDir))
                {
                    errMsg = "Cannot find directory '" + srcDir + "'";
                }

                arrFilesName = Directory.GetFiles(srcDir);

                s = new ZipOutputStream(File.Create(zipFilePath));

                try
                {
                    // 0 - 9  ， 9为最高压缩   
                    s.SetLevel(9);
                    btBuffer = new byte[4096];

                    foreach (string file in arrFilesName)
                    {
                        zipEntry = new ZipEntry(Path.GetFileName(file));
                        zipEntry.DateTime = DateTime.Now;
                        s.PutNextEntry(zipEntry);

                        using (FileStream fs = File.OpenRead(file))
                        {
                            do
                            {
                                scBytes = fs.Read(btBuffer, 0, btBuffer.Length);
                                s.Write(btBuffer, 0, scBytes);
                            } while (scBytes > 0);
                        }
                    }
                }
                catch (Exception ex)
                {
                    errMsg = ex.Message;
                }
                finally
                {
                    s.Finish();
                    s.Close();
                }
            }

            /// <summary>
            ///　压缩文件夹
            /// </summary>
            /// <param name="srcDir">待压缩的文件夹物理路径</param>
            /// <param name="zipFilePath">压缩后的zip文件路径（包括文件名）</param>
            /// <param name="isRecursive">是否递归压缩</param>
            /// <returns>异常信息</returns>
            public string ToZip(string srcDir, string zipFilePath, bool isRecursive)
            {
                string errMsg;
                FileStream zipFileStream;
                ZipOutputStream zipOutStream;

                errMsg = string.Empty;

                if (isRecursive == false)
                {
                    CreateZipByDictory(srcDir, zipFilePath, out errMsg);
                }
                else
                {
                    zipFileStream = File.Create(zipFilePath);
                    zipOutStream = new ZipOutputStream(zipFileStream);

                    try
                    {
                        CompressFolder(srcDir, zipOutStream, srcDir);
                    }
                    catch (Exception ex)
                    {
                        errMsg = ex.Message;
                    }
                    finally
                    {
                        zipOutStream.Finish();
                        zipOutStream.Close();
                    }
                }

                if (!File.Exists(zipFilePath) && (string.IsNullOrEmpty(errMsg) || errMsg.Trim() == ""))
                {
                    errMsg = "生成压缩文件失败";
                }

                return errMsg;
            }

            /// <summary>
            /// 压缩某个子文件夹
            /// </summary>
            /// <param name="srcDir">子文件夹物理路径</param>
            /// <param name="zipOutStream"></param>
            /// <param name="srcFolderName">压缩文件夹根路径</param>     
            void CompressFolder(string srcDir, ZipOutputStream zipOutStream, string srcFolderName)
            {
                string[] arrFilePath, arrDirPath;

                arrFilePath = Directory.GetFiles(srcDir);
                arrDirPath = Directory.GetDirectories(srcDir);

                if (File.Exists(srcDir))
                {
                    AddFileToZip(srcDir, zipOutStream, srcFolderName);
                    return;
                }

                foreach (string filePath in arrFilePath)
                {
                    AddFileToZip(filePath, zipOutStream, srcFolderName);
                }

                foreach (string folderName in arrDirPath)
                {
                    CompressFolder(folderName, zipOutStream, srcFolderName);
                }
            }

            /// <summary>
            ///　添加子文件至压缩包中
            /// </summary>
            /// <param name="filePath">文件路径</param>
            /// <param name="zipOutStream"></param>
            /// <param name="srcFolderName"></param>
            void AddFileToZip(string filePath, ZipOutputStream zipOutStream, string srcFolderName)
            {
                FileStream fStream;
                string currPath;
                int fsSize;
                ZipEntry zipEntry;
                byte[] zipBuffer;

                try
                {
                    fStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                    currPath = filePath.Replace(srcFolderName, "");

                    zipEntry = new ZipEntry(currPath);
                    zipOutStream.PutNextEntry(zipEntry);
                    zipBuffer = new byte[16384];
                    fsSize = fStream.Read(zipBuffer, 0, zipBuffer.Length);
                    zipOutStream.Write(zipBuffer, 0, fsSize);

                    try
                    {
                        while (fsSize < fStream.Length)
                        {
                            int sizeRead = fStream.Read(zipBuffer, 0, zipBuffer.Length);
                            zipOutStream.Write(zipBuffer, 0, sizeRead);
                            fsSize += sizeRead;
                        }
                    }
                    catch (System.Exception ex)
                    {
                        throw ex;
                    }
                    finally
                    {
                        fStream.Close();
                    }
                }
                catch (Exception e)
                {
                    throw e;
                }
            }

            /// <summary>
            /// 解压文件
            /// </summary>
            /// <param name="zipPath">压缩文件路径</param>
            /// <param name="unZipDirecotyPath">解压缩目录路径</param>
            /// <param name="zipPwd">解压密码</param>
            public void UnZip(string zipPath, string unZipDirecotyPath, string zipPwd)
            {
                //检查路径是否以"\"结尾
                while (unZipDirecotyPath.LastIndexOf("\\") + 1 == unZipDirecotyPath.Length)
                {
                    unZipDirecotyPath = unZipDirecotyPath.Substring(0, unZipDirecotyPath.Length - 1);//如果是则去掉末尾的"\"
                }

                UnZip(File.OpenRead(zipPath), unZipDirecotyPath, zipPwd);
            }

            /// <summary>
            /// 解压文件
            /// </summary>
            /// <param name="fileStream">压缩文件流</param>
            /// <param name="unZipDirecotyPath">解压缩目录路径</param>
            /// <param name="zipPwd">解压密码</param>
            public void UnZip(Stream fileStream, string unZipDirecotyPath, string zipPwd)
            {
                byte[] buffer;
                ZipEntry zipEntry;
                string fileDirPath, fileName;
                int fileSize;

                buffer = new byte[2048];

                //检查路径是否以"\"结尾
                while (unZipDirecotyPath.LastIndexOf("\\") + 1 == unZipDirecotyPath.Length)
                {
                    unZipDirecotyPath = unZipDirecotyPath.Substring(0, unZipDirecotyPath.Length - 1);//如果是则去掉末尾的"\"
                }

                using (ZipInputStream zipStream = new ZipInputStream(fileStream))
                {
                    zipEntry = null;
                    //判断Password
                    if (zipPwd != null && zipPwd.Length > 0)
                    {
                        zipStream.Password = zipPwd;
                    }

                    while ((zipEntry = zipStream.GetNextEntry()) != null)
                    {
                        fileDirPath = Path.GetDirectoryName(zipEntry.Name);
                        fileName = Path.GetFileName(zipEntry.Name);

                        if (!string.IsNullOrEmpty(fileDirPath))
                        {
                            Directory.CreateDirectory(unZipDirecotyPath + @"\" + fileDirPath);
                        }

                        if (!string.IsNullOrEmpty(fileName))
                        {
                            if (zipEntry.IsDirectory)
                            {
                                fileDirPath = Path.GetDirectoryName(unZipDirecotyPath + @"\" + zipEntry.Name);
                                Directory.CreateDirectory(fileDirPath);
                            }

                            using (FileStream stream = File.Create(unZipDirecotyPath + @"\" + zipEntry.Name))
                            {
                                while (true)
                                {
                                    fileSize = zipStream.Read(buffer, 0, buffer.Length);

                                    if (fileSize > 0)
                                    {
                                        stream.Write(buffer, 0, fileSize);
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }

        }
    }
}
